原始题目:剑指 Offer 26. 树的子结构 (opens new window)

解题思路:

如果 BBAA 的子结构,则 BB 的根节点可能是 AA 中的任意一节点,因此需要遍历A 的所有节点 nAnA,判断 B 是否是 nAnA 的子结构。

  1. 先序遍历 AA 的每个节点 nAnA
  2. 如果 AABB 都为 nullnull,根据题意直接返回 falsefalse
  3. 判断以 nAnA 为根节点的树是否包含树 BB
    1. 如果 BBnullnull,那么检查完毕,返回 truetrue
    2. 如果 AAnullnull 或者 AABB 的值不相等,那么 BB 肯定不是子结构,返回 falsefalse
    3. 检查 BB 的左子树 是否为 nAnA 的左子树的子结构,并且检查 BB 的右子树是否为 nAnA 的右子树的子结构。

代码:

public boolean isSubStructure(TreeNode A, TreeNode B) {
    return (A != null && B != null)
            && (recur(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B));
}

private boolean recur(TreeNode nA, TreeNode B) {
    if (B == null) {
        return true;
    }
    if (nA == null || nA.val != B.val) {
        return false;
    }
    return recur(nA.left, B.left) && recur(nA.right, B.right);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

复杂度分析

  • 时间复杂度O(MN)O(MN):其中 MMNN 分别为 AA 树和 BB 树的数量。先序遍历 AA 树占用 O(M)O(M),每次调用 recur 最多占用 O(N)O(N)

  • 空间复杂度O(M)O(M):当树 AA 和树 BB 都退化为链表时,递归调用深度最大。当 MNM \leq N 时,遍历树 AA 与递归判断的总递归深度为 MM ;当 M>NM>N 时,最差情况为遍历至树 AA 叶子节点,此时总递归深度为 MM

上次更新: 2023/10/15